import cgi
import datetime
import logging
import os

from google.appengine.api import images
from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template

from pygments import highlight
from pygments.lexers import PythonLexer
from pygments.formatters import HtmlFormatter

from model import BlogEntry
from model import CommentEntry
from model import DbFile

import BlogRender

class MainPage(webapp.RequestHandler):
    """The root page by which all Request handlers in the applicaiton should subclass"""
    def get(self):
        self.generate('base.html')
      
    def generate(self, template_name, template_values={}):
        """Base classes should call this instead of generatign their own template.
        This will generate all the base class template values and append the subclasses
        template values.  It then calls the template and writes the result to the browser"""
        user = users.get_current_user()
        recentBlogs = BlogEntry.gql("ORDER BY create_date DESC LIMIT 6")
        if not recentBlogs:
            recentBlogs = []
        
        values = {
            'request': self.request,
            'user': users.get_current_user(),
            'recentBlogs': recentBlogs,
            'login_url': users.create_login_url(self.request.uri),
            'logout_url': users.create_logout_url(self.request.uri),
            'debug': self.request.get('deb'),
            'isAdmin': users.is_current_user_admin(),
            'application_name': 'Code Blogger',}
        values.update(template_values)
        directory = os.path.dirname(__file__)
        path = os.path.join(directory, os.path.join('templates', template_name))
        self.response.out.write(template.render(path, values, debug=True))


class CreateEditBlog(MainPage):
    """Allows users to create and Edit Blogs.  This uses both get
    and post methods.  The get method will display the edit screen
    the post method will create/edit the blog entry"""
    def get(self):
        """Display the edit blog create"""
        if not users.is_current_user_admin():
            return self.redirect(users.create_login_url(self.request.uri))
        template_values = {}
        blogEntryKey = self.request.get("blog_id")
        if blogEntryKey:
            editBlog = BlogEntry.get(blogEntryKey)
            template_values['editBlog'] = editBlog            
        
        self.generate('CreateEditBlog.html', template_values)

    def post(self):
        """Accept a create/edit change to a blog entry"""
        user = users.get_current_user()
        if not users.is_current_user_admin():
            return self.redirect(users.create_login_url(self.request.uri))
        
        newBlogTitle = self.request.get('titleInput')
        newBlogMarkdown = self.request.get('textarea')
        editBlogKey = self.request.get('EditBlogKey')
        logging.log(logging.INFO, "User: " + user.email() + " posted create.do with Title: " +
                    newBlogTitle + "\nText ***\n" + newBlogMarkdown + "\n***")
        blogEntry = BlogEntry()
        if editBlogKey:
            blogEntry = BlogEntry.get(editBlogKey)
        blogEntry.author = user
        blogEntry.title = newBlogTitle
        blogEntry.markdown = newBlogMarkdown
        blogEntry.html = BlogRender.render(newBlogMarkdown)
        
        blogEntry.put()

        self.redirect('/ViewBlogEntry?blog_id=%s' % blogEntry.key()) #redirect to the newly created blog post


class AddCommentToBlogDo(MainPage):
    def post(self):
        editBlogKey = self.request.get('EditBlogKey')
        blogEntry = BlogEntry.get(editBlogKey)
        
        name = self.request.get('nameInput')
        title = self.request.get('titleInput')
        commentText = self.request.get('textarea')
        isHuman = self.request.get('isHuman')
        
        logging.log(logging.INFO, "Creating comment with Blog: " + blogEntry.title + " name: " + name +
                    " title: " + title + " commentText: " + commentText + " isHuman: " + isHuman)
        # we have to submit a comment to a blog, make sure we have all the information we need
        if (editBlogKey == None) or (not isHuman) or (not title) or (not name) or (not commentText):
            return self.redirect('/') #TODO show them an error or something
    
        comment = CommentEntry()
        
        comment.blog = blogEntry
        comment.name = name
        comment.title = title
        comment.markdown = commentText
        comment.html = BlogRender.render(commentText)
        
        comment.put()
        
        self.redirect('/ViewBlogEntry?blog_id=%s' % blogEntry.key())  #redirect to blog with new comment


class ViewBlogEntry(MainPage):
    def get(self):        
        blogId = self.request.get("blog_id")
        if not blogId:
            return self.redirect('ViewAllEntries')
        self.generateByBlogId(blogId)
        
    def generateByBlogId(self, blogId):
        """Given a blog_id it will retrieve from the database and display"""
        blogEntry = db.get(blogId)
        template_values = {'blogEntry': blogEntry}
        commentsQuery = CommentEntry.gql('where blog=:blogEntry', blogEntry=blogEntry)
        comments = commentsQuery.fetch(100,0)
        template_values['comments'] = comments
        self.generate('ViewBlogEntry.html', template_values)


class ViewAllEntries(MainPage):
    """Show all the available blogs to the user in a grid"""
    def get(self):
        currentPage = self.request.get("page")
        if not currentPage:
            currentPage = 0
        else:
            currentPage = int(currentPage)
        query = BlogEntry.all() #db.GqlQuery("SELECT * FROM BlogEntry")
        numRecordsToFetch = 10
        totalRecords = query.count()
        totalPages = totalRecords / numRecordsToFetch
        if currentPage > totalPages:
            currentPage = totalPages
        blogEntries = query.fetch(numRecordsToFetch, numRecordsToFetch * currentPage)
        
        firstPage = 0
        previousPage = currentPage - 1
        nextPage = currentPage + 1
        lastPage = totalPages
        
        template_values = { 'blogEntries' : blogEntries }
        #if firstPage <> lastPage:
        
        if previousPage > firstPage:
            template_values['previousPage'] = str(previousPage)        
        if nextPage < lastPage:
            template_values['nextPage'] = str(nextPage)
        if firstPage <> lastPage:
            template_values['firstPage'] = str(firstPage) #needs string because zero evaluates to false
            template_values['currentPage'] = str(currentPage)
            template_values['lastPage'] = str(lastPage)
        
        self.generate('ViewAllEntries.html', template_values)
            

class DeleteBlogEntry(MainPage):
    def get(self):
        if not users.is_current_user_admin():
            return self.redirect(users.create_login_url(self.request.uri))        
        blogEntry = db.get(self.request.get("blog_id"))
        blogEntry.delete()
        self.redirect('/ViewAllEntries')
        

class DeleteCommentEntry(ViewBlogEntry):
    def get(self):
        if not users.is_current_user_admin():
            return self.redirect(users.create_login_url(self.request.uri))
        commentEntry = db.get(self.request.get("comment_id"))
        commentEntry.delete()
        blogId = self.request.get("blog_id")
        self.generateByBlogId(blogId)
         

class ExportAllBlogEntries(MainPage):
    def get(self):
        if not users.is_current_user_admin():
            return self.redirect(users.create_login_url(self.request.uri))
        self.response.headers['Content-Type'] = "text/xml"
        xml = '<?xml version="1.0" encoding="ISO-8859-1"?><Blog><BlogEntries>'
        blogEntries = BlogEntry.all()
        for blogEntry in blogEntries:
            xml = xml + blogEntry.to_xml()
        xml = xml + "</BlogEntries>"
        xml = xml + "<Comments>"
        comments = CommentEntry.all()
        for comment in comments:
            xml = xml + comment.to_xml()
        xml = xml + "</Comments></Blog>"
        self.response.out.write(xml)
        

class ViewNamedBlog(ViewBlogEntry):
    def get(self):
        uri = self.request.uri
        blogTitle = uri[uri.rfind('/') + 1:]
        blogTitle = blogTitle.replace("_", " ")
        query = BlogEntry.gql('where title = :title', title = blogTitle)
        blogEntry  = query.get()
        if blogEntry == None:
            self.error(404)
            self.response.out.write("Not found")
            return
        
        self.generateByBlogId(blogEntry.key())
        
class FileUpload(MainPage):
    def get(self):
        currentPage = self.request.get("page")
        if not currentPage:
            currentPage = 0
        else:
            currentPage = int(currentPage)
        query = DbFile.all() #db.GqlQuery("SELECT * FROM BlogEntry")
        numRecordsToFetch = 10
        totalRecords = query.count()
        totalPages = totalRecords / numRecordsToFetch
        if currentPage > totalPages:
            currentPage = totalPages
        dbFileEntries = query.fetch(numRecordsToFetch, numRecordsToFetch * currentPage)
        
        firstPage = 0
        previousPage = currentPage - 1
        nextPage = currentPage + 1
        lastPage = totalPages
        
        template_values = { 'dbFileEntries' : dbFileEntries }
        #if firstPage <> lastPage:
        
        if previousPage > firstPage:
            template_values['previousPage'] = str(previousPage)        
        if nextPage < lastPage:
            template_values['nextPage'] = str(nextPage)
        if firstPage <> lastPage:
            template_values['firstPage'] = str(firstPage) #needs string because zero evaluates to false
            template_values['currentPage'] = str(currentPage)
            template_values['lastPage'] = str(lastPage)
        
        self.generate("FileUpload.html", template_values)
        
    def post(self):
        thefile = self.request.params['file']
        myFile = DbFile(name=thefile.filename,
                        data=db.Blob(thefile.value),
                        type=thefile.type)
        myFile.put()
        self.response.out.write("<a href='?file=%s'>%s</a>"
                                % (thefile.filename,
                                   thefile.filename))
        self.redirect("/FileUpload")

class DeleteFile(MainPage):
    def get(self):
        if not users.is_current_user_admin():
            return self.redirect(users.create_login_url(self.request.uri))        
        fileEntry = db.get(self.request.get("file_id"))
        fileEntry.delete()
        self.redirect('/FileUpload')

class DownloadFile(ViewBlogEntry):
    def get(self):
        uri = self.request.uri
        fileName = uri[uri.rfind('/') + 1:]
        query = DbFile.gql('where name = :name', name = fileName)
        fileEntry  = query.get()
        if fileEntry == None:
            self.error(404)
            self.response.out.write("Not found")
            return
        else:
            self.response.headers['Content-Type'] = fileEntry.type
            self.response.out.write(fileEntry.data)
                
def main():
    application = webapp.WSGIApplication([
      ('/', MainPage),
      ('/CreateEditBlog', CreateEditBlog),
      ('/ViewBlogEntry', ViewBlogEntry),
      ('/ViewAllEntries', ViewAllEntries),
      ('/DeleteBlogEntry', DeleteBlogEntry),
      ('/ExportAllBlogEntries', ExportAllBlogEntries),
      ('/articles/.*', ViewNamedBlog),
      ('/AddCommentToBlog.do', AddCommentToBlogDo),
      ('/DeleteCommentEntry', DeleteCommentEntry),
      ('/FileUpload', FileUpload),
      ('/DeleteFile', DeleteFile),
      ('/Files/.*', DownloadFile)
      ], debug=True)    
    run_wsgi_app(application)

if __name__ == '__main__':
    main()
